#include <iostream>
#include <typeinfo>

// 讲了模板以后，在调函数的时候类型会变成通用的T类型，这样一来有时候函数就会变得不太可控

// 一般类型
template <typename T>
void print(const T &a)
{
    // RTTI：运行时类型信息
    // 运行期需要知道变量的类型是什么
    // typeid关键字
    // 如果传进来的T是int类型，就在前面打印个int
    if (typeid(a) == typeid(int))
        std::cout << "int:";
    // 如果传进来的T是string类型，就在前面打印个string
    if (typeid(a) == typeid(std::string))
        std::cout << "string:";

    std::cout << a << std::endl;
}

// 继承类型
class Base
{
public:
    // 只有在有虚函数的情况下，基类指针解引用的类型才会识别为子类
    virtual void show()
    {
        std::cout << "Base" << std::endl;
    }
};

class Derived : public Base
{
public:
    void show()
    {
        std::cout << "Derived" << std::endl;
    }
};

int main()
{
#if 0
    print(1);
    print(std::string("hello"));
#endif

#if 0
    // typeid关键字是有函数的
    // 因为它返回的是个对象（type_info）
    // typeid会返回一个叫type_info的类，这个类有很多的参数
    const std::type_info &info1 = typeid(int);
    const std::type_info &info2 = typeid(int *);
    // 类型的名称（不同编译器用的类型名称不同）
    std::cout << info1.name() << std::endl;
    std::cout << info2.name() << std::endl;
    // 类型的唯一标识符，相当于类型的id（类型的身份证），通过这个能找到这个类型
    std::cout << info1.hash_code() << std::endl;
    std::cout << info2.hash_code() << std::endl;
#endif

#if 1
    // 只有在有虚函数的情况下，基类指针解引用的类型才会识别为子类
    Base *b = new Derived; // 用基类指针指向子类对象

    // 1：说明b是Base类型的指针
    std::cout << (typeid(b) == typeid(Base *)) << std::endl;
    // 1：说明指针b指向的对象是个Base
    // 说明它认new Derived这个对象是个父类
    // 因为没用多态
    // 没有多态，typeid只会指出原本指针所在类型，不认子类对象
    // 只有在多态的时候，指针b指向的对象才会认为是子类对象，只有有多态的时候才会生效
    // 光继承不行，必须要有虚函数
    std::cout << (typeid(*b) == typeid(Base)) << std::endl;
#endif

    return 0;

    // dynamic_cast之所以能在运行期检查指针能否转换，其原理就是使用的typeid，也就是RTTI
    // 跑到基类和子类代码里一个一个找，看看类型符不符合，如类型符合就可以转，反之不可以转
    // 效率比较低，有一个检查的过程，这个检查是一个一个去对，看typeid是不是和它一样的，一样就可以转，不一样就不给转
}